import React, { useEffect, useRef, useState, forwardRef, useImperativeHandle, useCallback } from 'react';
import _ from 'lodash';
import { callAIChat, getAgentInfo, getChatMessageStream } from '../../apis/public/chat';
import { generateDownloadToken } from '../../apis/public/fileUpDownload';
import { uploadFile } from '../../apis/public/upload';
import { observer } from 'mobx-react-lite';
import { ChatProps, ChatRef, AgentInfo, default_empty_message, default_error_message } from './chatType';
import './chat.css';
import { Chat } from '@douyinfe/semi-ui';
import { UUID } from '../../utils/uuid';
import { Message } from '@douyinfe/semi-foundation/lib/es/chat/foundation';
import bannerImg from '@/assets/banner.png';
import CustomActions from './ChatActions';
import { Chat_Default_Directory, Editor_Default_Directory } from '../../globals/document';
import { Agent_System_Chat } from '../../globals/agent';
import { getContentByFileId } from '@/apis/public/fileUpDownload';
import { getBlobUrl } from '@/utils/fileUtil';

const roleInfo = {
  assistant: {
    name: '智能助手',
    avatar: bannerImg
  },
  system: {
    name: 'System',
    avatar: bannerImg
  }
}

const ChatCom = observer(forwardRef<ChatRef, ChatProps>((props, ref) => {
  const {
    agentId,                                // 智能体ID
    mode = 'div',                          // 显示模式
    initialCollapsed = false,              // 初始折叠状态
    position,                              // 弹窗位置
    onMessage,                            // 消息回调
    onRenderComplete,                     // 渲染完成回调
    onStreamMessage,                      // 流式消息回调
    onClose,                              // 关闭回调
    bindRef,                              // 绑定ref方法
    className,                            // 自定义类名
    style,                                // 自定义样式
    getAdditionalParams,                  // 获取额外参数的方法
    promptName,                           // 指定的prompt名称
    functionName,                         // 指定的function名称
    renderWelcome,                        // 欢迎语渲染钩子
    renderHintBox,                        // 提示框渲染钩子
    sessionId,                            // 会话ID
    ...restProps
  } = props;


  const uploadTipProps = { content: '自定义上传按钮提示信息' }

  const [curAgentId, setCurAgentId] = useState(agentId);
  const [curSessionId, setCurSessionId] = useState<string>(sessionId || '');
  const [agentInfo, setAgentInfo] = useState<AgentInfo | null>();
  const [message, setMessage] = useState<Message[]>([]);
  const [messageStatus, setMessageStatus] = useState<Record<string, 'opening' | 'complete' | 'cancel' | 'error'>>({});
  const [curMessageId, setCurMessageId] = useState<string>();
  const [error, setError] = useState<string | null>(null);
  const [documentContents, setDocumentContents] = useState<Record<string, string>>({});
  const documentContentsRef = useRef(documentContents);
  const [userAvatarBlobUrl, setUserAvatarBlobUrl] = useState<string>('');

  // 每次 documentContents 变化时，同步 ref
  useEffect(() => {
    documentContentsRef.current = documentContents;
  }, [documentContents]);

  const aiRef = useRef<any>(null);

  const abortController = useRef<AbortController | null>(null);

  // 暴露方法给父组件
  useImperativeHandle(ref, () => ({
    sendMessage: async (content: string) => {
      if (!content.trim()) return;
      await handleSendMessage(content);
    },
    clearHistory: () => {
      aiRef?.current?.resetMessage();
    },
    changeAgent: async (newAgentId: string) => {
      return initAgent(newAgentId);
    },
    getHistory: () => {
      return message;
    },
    changeSession: async (sessionId: string) => {
      setCurSessionId(sessionId);
      return true;
    },
    setHistoryMessages: (messages: Message[]) => {
      setMessage(messages);
    },
    newChat: () => {
      newChatSession();
    }
  }));

  /**
   * 初始化智能体
   */
  useEffect(() => {
    initAgent(agentId);
  }, [agentId]);

  const newChatSession = useCallback(() => {
    initAgent(curAgentId);
  }, [])

  /**
   * 初始化智能体
   */
  const initAgent = useCallback(async (newAgentId?: string) => {
    if (newAgentId) {
      setCurAgentId(newAgentId);
    }

    const currentAgentId = newAgentId || curAgentId;

    if (!currentAgentId) {
      return false;
    }

    try {
      const res = await getAgentInfo({ agentId: currentAgentId.toString() });

      if (res.status && res.code == 200) {
        const { sessionId, agentConfig } = res.data;
        setAgentInfo(agentConfig);
        setCurSessionId(sessionId);;

        const _welcomeMessage = agentConfig.welcomeMessage;
        const welcomeMessage: Message = {
          role: 'assistant',
          id: Agent_System_Chat,
          createAt: new Date().getTime(),
          content: _welcomeMessage,
        };

        setMessage([welcomeMessage]);
        return true;
      }
      return false;
    } catch (error) {
      console.error('Failed to initialize agent:', error);
      return false;
    }
  }, [curAgentId]);

  /**
   * 添加loading消息
   */
  const addLoadingMessage = useCallback(() => {
    const loadingMessage: Message = {
      id: UUID(),
      role: 'assistant',
      content: '',
      status: 'loading'
    }
    setMessage((message) => ([...message, loadingMessage]));
  }, []);

  /**
   * 添加用户消息
   */
  const addErrorMessage = useCallback(() => {
    const loadingMessage: Message = {
      id: UUID(),
      role: 'assistant',
      content: default_error_message,
      status: 'error'
    }
    setMessage((message) => ([...message, loadingMessage]));
  }, []);

  /**
   * 修改消息状态
   */
  const changeMessageStatus = useCallback((messageId: string, status: 'cancel' | 'complete' | 'error') => {
    setMessageStatus(prevStatus => {
      const oldStatus = prevStatus[messageId];
      if(oldStatus === 'opening') {
        return {...prevStatus, [messageId]: status};
      }
      return prevStatus;
    })
  }, [setMessageStatus]);

  /**
   * 删除loading消息
   */
  const removeLoadingMessage = useCallback(() => {
    setMessage((message) => message.filter((msg) => msg.status !== 'loading'));
  }, []);

  /**
   * 删除指定ID消息
   */
  const removeMessageById = useCallback((id: string) => {
    setMessage((message) => message.filter((msg) => msg.id !== id));
  }, []);

  /**
   * 发送消息(非流式)
   */
  const handleSendMessage = useCallback(async (messageId: string, content?: string, attachment?: any) => {
    const messageContent: string = content || '';
    if (!messageContent.trim()) return;

    // 添加loading消息
    addLoadingMessage();

    let additionalParams = typeof getAdditionalParams === 'function' ? getAdditionalParams() : {};

    const params = {
      userId: window.HubUser?.id,
      sessionId: curSessionId,
      userMessage: content,
      agentId: curAgentId,
      additionalParams: {
        ...additionalParams,
        documents: Object.values(documentContentsRef.current).join('\n\n')
      },
      promptName: promptName,
      functionName: functionName
    };

    // 处理返回对话内容
    callAIChat(params as any).then(res => {
      // 获取最新的 messageStatus
      setMessageStatus(prevStatus => {
        const status = prevStatus[messageId];
        if(status === 'opening') {
          //删除loading消息
          removeLoadingMessage();
          if (res.status && res.code == 200) {
            const { chatSessionId, message } = res.data;
            const newMessage = onSuccessMessage(chatSessionId, message, messageId);
            // 消息回调
            onMessage && onMessage(newMessage, curSessionId || '', chatSessionId, params);
            //清空当前消息ID
            curMessageId === messageId && setCurMessageId('');
            return {...prevStatus, [messageId]: 'complete'};
          }else {
            onErrorMessage(messageId)
            return {...prevStatus, [messageId]: 'error'};
          }
        }
        return prevStatus;
      });
      //清空文档内容
      setDocumentContents({});
    }).catch(err => {
      // 获取最新的 messageStatus
      setMessageStatus(prevStatus => {
        const status = prevStatus[messageId];
        if(status === 'opening') {
          onErrorMessage(messageId);
          return {...prevStatus, [messageId]: 'error'};
        }
        return prevStatus;
      });
      //清空文档内容
      setDocumentContents({});
    })
  }, [curAgentId, curSessionId, addLoadingMessage, removeLoadingMessage, addErrorMessage, getAdditionalParams, promptName, functionName, onMessage, curMessageId, setCurMessageId]);


  /**
   * 成功消息
   */
  const onSuccessMessage = useCallback((chatSessionId: string, message: string, messageId: string) => {
    const newMessage: Message = {
      role: 'assistant',
      id: messageId || UUID(),
      createAt: Date.now(),
      content: message || default_empty_message,
    }
    setMessage((message) => ([...message, newMessage]));
    return newMessage;
  }, [setMessage]);

  /**
   * 错误消息
   */
  const onErrorMessage = useCallback((messageId: string) => {
    removeLoadingMessage();
    addErrorMessage();
    setError('发送消息失败');
    //清空当前消息ID
    curMessageId === messageId && setCurMessageId('');
  }, [setMessage, removeLoadingMessage, curMessageId, setCurMessageId]);

  /**
   * 发送消息(流式)
   */
  const handleSendMessageStream = useCallback(async (messageId: string, content?: string, attachment?: any) => {
    const messageContent: string = content || '';
    if (!messageContent.trim()) return;

    // 创建 AbortController 实例
    const abortController = new AbortController();

    // 添加loading消息
    addLoadingMessage();

    try {
      let additionalParams = typeof getAdditionalParams === 'function' ? getAdditionalParams() : {};
      const params = {
        userId: window.HubUser?.id,
        sessionId: curSessionId,
        userMessage: content,
        agentId: curAgentId,
        additionalParams,
        promptName: promptName,
        functionName: functionName
      };

      let messageContent = "";
      let outputing = false;
      getChatMessageStream(params, (text) => {
        //about
      }, (chunk) => {
        if (chunk.type == "text") {
          messageContent += chunk.text;
          if (!outputing) {
            //输出完成时
            outputing = true;
            let newMessage: Message = {
              role: 'assistant',
              id: UUID(),
              createAt: Date.now(),
              content: messageContent,
            }
            //删除loading消息
            removeLoadingMessage();
            //添加消息
            setMessage((prevMessage) => ([...prevMessage, newMessage]));
            //清空当前消息ID
            curMessageId === messageId && setCurMessageId('');
            //清空文档内容
            setDocumentContents({});
          } else {
            // 使用函数式更新获取最新的 message
            setMessage(prevMessage => {
              const _message = _.cloneDeep(prevMessage);
              const lastMessage = _message[_message.length - 1];
              lastMessage.content = messageContent;
              _message.pop();
              _message.push(lastMessage);
              return _message;
            });
          }
        }
      }, (text) => {
        //finish
        removeLoadingMessage();
        //清空当前消息ID
        curMessageId === messageId && setCurMessageId('');
        //清空文档内容
        setDocumentContents({});
      }, abortController.signal); // 传入 signal

      // 将 abortController 保存到 ref 中，以便其他地方可以访问
      aiRef.current = {
        ...aiRef.current,
        abortController
      };

    } catch (err) {
      removeLoadingMessage();
      addErrorMessage();
      setError('发送消息失败');
      //清空当前消息ID
      setCurMessageId('');
      //清空文档内容
      setDocumentContents({});
    }
  }, [curAgentId, curSessionId, addLoadingMessage, removeLoadingMessage, addErrorMessage, getAdditionalParams, promptName, functionName, curMessageId, setCurMessageId]);

  /**
   * 消息变化
   */
  const onChatsChange = useCallback((chats) => {
    setMessage(chats);
  }, []);

  /**
   * 消息发送
   */
  const onMessageSend = useCallback((content: string, attachment?: any) => {
    // 获取当前消息ID
    const messageId = UUID();
    //设置当前消息状态
    setCurMessageId(messageId);
    messageStatus[messageId] = 'opening';
    setMessageStatus({...messageStatus});

    if (agentInfo?.isStreaming == 1) {
      handleSendMessageStream(messageId, content, attachment);
    } else {
      handleSendMessage(messageId, content, attachment);
    }
  }, [agentInfo, handleSendMessage, handleSendMessageStream, curMessageId, setCurMessageId, messageStatus, setMessageStatus]);


  /**
   * 消息重新发送接口
   */
  const onMessageReset = useCallback((e) => {

  }, [])


  /**
   * 文件上传
   * @param param0 
   */
  const customRequest = async ({ file, onSuccess, onError }: any) => {
    const directory = Chat_Default_Directory;
    try {
      // 拼接文件上传参数
      const formData = new FormData();
      formData.append('uid', file?.fileInstance?.uid);
      formData.append('file', file?.fileInstance);
      formData.append('fileName', file?.fileInstance?.name);
      formData.append('directoryId', directory.toString());
      const response = await uploadFile(formData);

      getContent(response)
      onSuccess(file);

      //文件内容提取
      // onUploadSuccess(file); // 调用上传成功回调函数
    } catch (error) {
      onError(error);
    }
  };

  /**
   * 文件内容提取
   * @param response
   * @param type
   */
  const getContent = useCallback(async (response: any) => {
    const fileId = response.data.page?.[0].id;
    if(fileId){
      const res = await getContentByFileId({
        id: fileId,
        fileName: '',
        filePath: '',
        directoryId: Editor_Default_Directory,
        userId: Number(window.HubUser?.id),
        pageNo: 0,
        pageSize: 0,
        html: ''
      });
      if(res.code == 200 && res.data.success){
        setDocumentContents(prevDocument => {
          const newDocument = {...prevDocument, [fileId]: res.data.content};
          return newDocument;
        });
      }
    }
  }, []);

  const uploadProps = { customRequest: customRequest, action: '/api/starhub/document/addDocumentInfo' };

  /**
   * 添加用户取消消息
   */
  const addCancelMessage = useCallback((curMessageId: string) => {
    const loadingMessage: Message = {
      id: curMessageId,
      role: 'assistant',
      content: '已取消本次回答',
    }
    setMessage((message) => ([...message, loadingMessage]));
  }, []);

  /**
   * 取消当前对话
   */
  const onStopGenerator = useCallback((chats) => {
    if(curMessageId) {
      // 调用 abortController 的 abort 方法停止请求
      if (aiRef.current?.abortController) {
        aiRef.current.abortController.abort();
      }
      
      changeMessageStatus(curMessageId, 'cancel');
      removeLoadingMessage();
      addCancelMessage(curMessageId)
      setCurMessageId('');
    }
  }, [curMessageId, changeMessageStatus]);

  const commonOuterStyle = {
    border: '1px solid var(--semi-color-border)',
    borderRadius: '16px',
    margin: '8px 16px',
    height: '100%',
    maxWidth: '100%',
    width: 'calc(100% - 32px)'
  }

  // 监听props.sessionId变化，自动同步到curSessionId
  useEffect(() => {
    if (props.sessionId) {
      setCurSessionId(props.sessionId);
    }
  }, [props.sessionId]);

  const customRenderAction = useCallback((props) => {
    return <CustomActions {...props} />
  }, []);


  // 获取用户头像的 blobUrl
  useEffect(() => {
    const fetchUserAvatar = async () => {
      if (window?.HubUser?.avatar) {
        const blobUrl = await getBlobUrl(window.HubUser.avatar);
        setUserAvatarBlobUrl(blobUrl);
      }
    };
    fetchUserAvatar();

    // 组件销毁时清除 blobUrl
    return () => {
      if (userAvatarBlobUrl) {
        URL.revokeObjectURL(userAvatarBlobUrl);
      }
    };
  }, []);

  const getChatRole: any = useCallback(() => {
    return {
      ...roleInfo,
      user: {
        name: window?.HubUser?.name,
        avatar: userAvatarBlobUrl || bannerImg
      }
    }
  }, [userAvatarBlobUrl]);

  // 默认div模式
  return (
    props.hideChat ? null :
      <div className="chat-container" style={{ position: 'relative' }}>
        <Chat
          ref={aiRef}
          key='leftRightbubble'
          align='leftRight'
          mode='bubble'
          showStopGenerate={true}
          onStopGenerator={onStopGenerator}
          uploadProps={uploadProps}
          //style={commonOuterStyle}
          chats={message as any}
          roleConfig={getChatRole()}
          onChatsChange={onChatsChange}
          onMessageSend={onMessageSend}
          onMessageReset={onMessageReset}
          uploadTipProps={uploadTipProps}
          chatBoxRenderConfig={{
            renderChatBoxAction: customRenderAction
          }}
        />
      </div>
  );
}));

export default ChatCom;
